#include "stdafx.h"
#include "ServiceImpHost.h"
#include "SessionCM.h"
#include "Message/MsgCategory.h"
#include "Message/MsgBuilderSimple.h"
#include "Message/MsgSession.h"



ServiceImpHost::ServiceImpHost()
:m_theEmptyWork(m_theIoSvc),
m_theAcceptor(m_theIoSvc),
m_wpSvcLgc(NULL),
m_pMsgBuilder(NULL),
m_nCurrentSessionID(1),
m_nPort(9000)
{
}

ServiceImpHost::~ServiceImpHost()
{

}

void
ServiceImpHost::init(ServiceData& data)
{
	ServiceDataSMS* pSvcData = dynamic_cast<ServiceDataSMS*>(&data);
	if (pSvcData)
	{
		m_wpSvcLgc = pSvcData->m_wpSvcLgc;

		if (!pSvcData->m_wpProperties->parse("service_port", m_nPort))
		{
			LOG_DEBUG("Failed to get server listen port from properties!\n");
		}
	}

	if (m_pMsgBuilder==NULL)
	{
		m_pMsgBuilder = new MsgBuilderWithFactory;
	}
}

void
ServiceImpHost::onStart()
{

	m_theEndPoint.port(m_nPort);

	m_theAcceptor.open(boost::asio::ip::tcp::v4());

	m_theAcceptor.bind(m_theEndPoint);

	m_theAcceptor.listen();

	post_accept();
	post_accept();

	__super::onStart();
}

void
ServiceImpHost::onStop()
{
	__super::onStop();
}

bool 
ServiceImpHost::createSession(Session*& pSession)
{
	pSession = new SessionCM(m_theIoSvc, m_wpSvcLgc, this, m_pMsgBuilder);
	pSession->setDataStreamPool(&m_theMsgBuffFact);
	return true;
}

bool
ServiceImpHost::releaseSession(Session* pSession)
{
	if (pSession)
	{
		delete pSession;
	}
	return true;
}

Session*
ServiceImpHost::getSession(int sid)
{
	SessionMap::const_iterator it = m_mapSID2Session.find(sid);
	if (it==m_mapSID2Session.end())
	{
		return NULL;
	}
	else
	{
		return it->second;
	}
}

void
ServiceImpHost::rmvSession(int sid)
{
	Session* pSession = getSession(sid);

	if (pSession!=NULL)
	{
		m_mapSID2Session.erase(pSession->getID());

		releaseSession(pSession);
	}
	else
	{
		LOG_DEBUG("Failed to remove session : "<<sid);
	}
}



void 
ServiceImpHost::onSessionStart(Session* pSes, const boost::system::error_code& error)
{
	if (pSes!=NULL && !error)
	{
		LOG_DEBUG(" ******************************************!!!");
		LOG_DEBUG(" net connectiong in, Network thread!!!");

		//
		//	To find a unused session id
		while (m_nCurrentSessionID==0 || getSession(m_nCurrentSessionID))
		{
			m_nCurrentSessionID++;
		}
		pSes->setID(m_nCurrentSessionID);
		m_mapSID2Session[m_nCurrentSessionID++] = pSes;

		pSes->read();
		pSes->read();
		pSes->read();
	}

	post_accept();
}

void
ServiceImpHost::onSessionEnd(Session* pSes)
{
	if (pSes)
	{
		releaseSession(pSes);
	}
}

void
ServiceImpHost::onTimer()
{
	LOG_DEBUG(" TO,N, SCnt: "<<m_mapSID2Session.size());
	__super::onTimer();
}

void
ServiceImpHost::onDispatchMsg(IMsg* pMsg)
{
	//LOG_DEBUG(" Dispatch Message, Network Thread!!!");
	if (pMsg)
	{
		if (pMsg->getMsgCate()==Msg::MC_Control)
		{
			onControlMsg(pMsg);
		}
		else
		{
			Session* pSession = getSession(pMsg->getSID());
			if (pSession)
			{
				pSession->write(pMsg);
			}
			else
			{
				pMsg->dump();
				LOG_ERROR("Failed push upper message to network, invalid session: "<<pMsg->getSID());
			}
		}

		delete pMsg;
	}
}

void 
ServiceImpHost::onControlMsg(IMsg* pMsg)
{
	switch (pMsg->getMsgID())
	{
	case MsgSessionClosed::Id:
		{
			MsgSessionClosed* msg = dynamic_cast<MsgSessionClosed*>(pMsg);
			if (msg)
			{
				rmvSession(msg->m_nSessionID);
			}
			break;
		}
	/*case MsgSessionUpdate::Id:
		{
			MsgSessionUpdate* msg = dynamic_cast<MsgSessionUpdate*>(pMsg);
			if (msg)
			{
				Session* pSession = getSession(msg->m_nSessionID);

				if (pSession)
				{
					if (pSession->getSID()==0)
					{
						m_mapEID2Session[pMsg->getSID()] = pSession;
					}
					
					pSession->setSID(pMsg->getSID());
				}
			}
			break;
		}*/
	}
}


void
ServiceImpHost::post_accept()
{
	Session* pNewSes =  NULL;
	if (createSession(pNewSes))
	{
		m_theAcceptor.async_accept(pNewSes->getSocket(), boost::bind(&ServiceImpHost::onSessionStart, this, pNewSes, boost::asio::placeholders::error));
	}
}